/*
 * @Author       : Bing Chen chenbing@iocharger.com
 * @Date         : 2024-05-30 14:48:01
 * @LastEditors  : Bing Chen chenbing@iocharger.com
 * @LastEditTime : 2025-03-17 09:21:39
 * @FilePath     : \openchaoji-corelib\evcc\gbt27930\OpenChaoJi_evcc_gbt27930_system.c
 * @Description  : 本文件实现evcc系统状态机切换的基本逻辑
 *
 * Copyright (c) 2025 OpenChaoJi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the icense for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "OpenChaoJi_evcc.h"

const struct OpenChaoJi_evcc_module * OpenChaoJi_evcc_service_find_module(struct OpenChaoJi_evcc_gbt27930_system * evcc_gbt27930_system, const int module_status_id)
{
    const struct OpenChaoJi_evcc_module * module = NULL;

    int module_id = OPENCHAOJI_MODULE_OF_ID(module_status_id);

    for (int i = 0; i < evcc_gbt27930_system->module_array_len; i++)
    {
        module = evcc_gbt27930_system->module_array[i];

        if ((module != NULL) && (module->module_id == module_id))
        {
            return module;
        }
    }

    return NULL;
}

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
const struct OpenChaoJi_evcc_module * OpenChaoJi_evcc_service_find_module_by_fdc(struct OpenChaoJi_evcc_gbt27930_system * evcc_gbt27930_system, enum OpenChaoJi_gbt27930_b_FCType fc_type, uint8_t fdc_type)
{
    const struct OpenChaoJi_evcc_module * module = NULL;

    for (int i = 0; i < evcc_gbt27930_system->module_array_len; i++)
    {
        module = evcc_gbt27930_system->module_array[i];

        if ((module != NULL) && (module->fc_type == fc_type) && (module->fdc_type == fdc_type))
        {
            return module;
        }
    }

    return NULL;
}
#endif

/**
 * @brief: 根据一个全局的唯一状态id, 找到该系统的对应的状态处理机
 * @param {OpenChaoJi_evcc_gbt27930_system *} evcc_gbt27930_system 系统定义
 * @param {int} module_status_id 全局唯一状态id
 * @return {*} 该id对应的状态处理机
 */
const struct OpenChaoJi_evcc_module_status * OpenChaoJi_evcc_service_find_status(struct OpenChaoJi_evcc_gbt27930_system * evcc_gbt27930_system, const int module_status_id)
{
    const struct OpenChaoJi_evcc_module * module = NULL;

    int module_id = OPENCHAOJI_MODULE_OF_ID(module_status_id);

    for (int i = 0; i < evcc_gbt27930_system->module_array_len; i++)
    {
        module = evcc_gbt27930_system->module_array[i];

        if ((module == NULL) || (module->module_id != module_id))
        {
            continue;
        }

        for (int j = 0; j < module->status_array_len; j++)
        {
            if ((module->status_array + j)->module_status_id == module_status_id)
            {
                return (module->status_array + j);
            }
        }
    }

    return NULL;
}

const char * OpenChaoJi_evcc_module_name_func(struct OpenChaoJi_evcc_context * context, int module_status_id)
{
    const struct OpenChaoJi_evcc_module * module = NULL;

    int module_id = OPENCHAOJI_MODULE_OF_ID(module_status_id);

    for (int i = 0; i < context->active_evcc_gbt27930_system->module_array_len; i++)
    {
        module = context->active_evcc_gbt27930_system->module_array[i];

        if ((module != NULL) && (module->module_id == module_id))
        {
            if (module->name != NULL)
            {
                return module->name;
            }
            else
            {
                return "UndefinedModuleName";
            }
        }
    }

    return "UnknownModuleName";
}

const char * OpenChaoJi_evcc_status_name_func(struct OpenChaoJi_evcc_context * context, int module_status_id)
{
    const struct OpenChaoJi_evcc_module * module = NULL;

    int module_id = OPENCHAOJI_MODULE_OF_ID(module_status_id);

    for (int i = 0; i < context->active_evcc_gbt27930_system->module_array_len; i++)
    {
        module = context->active_evcc_gbt27930_system->module_array[i];

        if ((module == NULL) || (module->module_id != module_id))
        {
            continue;
        }

        for (int j = 0; j < module->status_array_len; j++)
        {
            if ((module->status_array + j)->module_status_id == module_status_id)
            {
                if ((module->status_array + j)->name != NULL)
                {
                    return (module->status_array + j)->name;
                }
                else
                {
                    return "UndefinedStatusName";
                }
            }
        }
    }

    return "UnknownStatusName";
}

/**
 * @brief: 状态切换处理, 需要执行旧状态的post方法, 再执行新状态的prev方法
 * @param {OpenChaoJi_evcc_context *} context 上下文
 * @param {int} next_status_id 下一个状态
 * @return {*} 无
 */
static void OpenChaoJi_evcc_service_switch_status(struct OpenChaoJi_evcc_context * context, int next_status_id)
{
    /* 只有状态发生变化才进行切换处理 */
    if (context->current_module_status_id != next_status_id)
    {
        const struct OpenChaoJi_evcc_module_status * old_status = OpenChaoJi_evcc_service_find_status(context->active_evcc_gbt27930_system, context->current_module_status_id);
        const struct OpenChaoJi_evcc_module_status * next_status = OpenChaoJi_evcc_service_find_status(context->active_evcc_gbt27930_system, next_status_id);
		LOG_STATUS_CHANGE("[%d]Switch %s[%08X]->%s[%08X]", context->tag
            , old_status->name, context->current_module_status_id
            , next_status->name, next_status_id);

        /* 离开旧状态 */
        if (old_status->post_func != NULL)
        {
            old_status->post_func(context);
        }

        /* 进入新状态 */
        if (next_status->prev_func != NULL)
        {
            next_status->prev_func(context);
        }

        /* 记录时间戳, 可能用于各种状态超时判断处理 */
        context->current_status_ticks = OpenChaoJi_os_get_ticks();
        context->current_module_status_id = next_status_id;
    }

    return;
}

void OpenChaoJi_evcc_switch_system(struct OpenChaoJi_evcc_context * context, struct OpenChaoJi_evcc_gbt27930_system * new_system)
{
    if (new_system == NULL)
    {
        return;
    }

    if (context->active_evcc_gbt27930_system != new_system)
    {
        LOG_WARNING("SYSTEM[%s->%s]", context->active_evcc_gbt27930_system->name, new_system->name);

        context->active_evcc_gbt27930_system->app_stop_func(context);
        context->active_evcc_gbt27930_system = new_system;
    }

    return;
}

/**
 * @brief: 当前系统的状态机主处理方法, 需要定时触发, 一般建议不超过20ms调用一次
 *         注意, 由于兼容非系统方式实现, 所以本项目所有方法默认处于同一线程, 如厂家通过操作系统实现, 厂家需要保证线程安全
 * @param {OpenChaoJi_evcc_context *} context
 * @return {*}
 */
void OpenChaoJi_evcc_service(struct OpenChaoJi_evcc_context * context)
{
    int next_status_id = 0;

    /* 会话层有独立的service驱动, 用于驱动导引和传输层 */
    OpenChaoJi_evcc_utility_session_service(context->context_session);

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    /*
     * EVCC系统需要根据连接的对端桩决定使用哪个系统, 所以这里还需要有切换系统的判断操作
     * 插枪/拔枪的时刻进行触发, 对 active_evcc_gbt27930_system 进行赋值
    */
    if (context->evcc_gbt27930_type == OPENCHAOJI_EVCC_GBT27930_TYPE_B)
    {
        if (!OpenChaoJi_evcc_utility_pilot_is_secc_connected(context->context_pilot))   // 拔枪状态下必须切换到B类系统
        {
            OpenChaoJi_evcc_switch_system(context, context->evcc_gbt27930_system_b);
        }
        else
        {
            // 插枪状态下, 如果是当前不是B类系统, 则保持不变, 直到拔枪
            // 如果当前是B类系统, 则需要判断对端桩类型, 如果是A类系统, 则切换到A类系统
            if (context->active_evcc_gbt27930_system == context->evcc_gbt27930_system_b)
            {
                // 由于B类系统进入自检前会断开Sv, 所以这里不能使用connected_secc_type, 需要使用B类系统确认的导引状态
                enum OpenChaoJi_secc_gbt27930_type confirmed_secc_type = OpenChaoJi_evcc_utility_pilot_b_confirmed_secc_type(context->context_pilot);
                if (confirmed_secc_type == OPENCHAOJI_SECC_GBT27930_TYPE_B)
                {
                    OpenChaoJi_evcc_switch_system(context, context->evcc_gbt27930_system_b);
                }
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
                else if (confirmed_secc_type == OPENCHAOJI_SECC_GBT27930_TYPE_A)
                {
                    OpenChaoJi_evcc_switch_system(context, context->evcc_gbt27930_system_a);
                }
#endif
                else    // 当前SECC类型未知时, 默认置于system_b状态
                {
                    OpenChaoJi_evcc_switch_system(context, context->evcc_gbt27930_system_b);
                }
            }
        }
    }
#endif

    /* 先查找到当前状态表 */
    const struct OpenChaoJi_evcc_module_status * status = OpenChaoJi_evcc_service_find_status(context->active_evcc_gbt27930_system, context->current_module_status_id);

    /* 执行当前状态表相关操作, 确认是否需要切换状态 */
    if (status != NULL)
    {
        /* 先从对端读取数据, 同步对端状态 */
        if (context->active_evcc_gbt27930_system->data_read_func != NULL)
        {
            context->active_evcc_gbt27930_system->data_read_func(context);
        }

        /* 先执行通用子过程, 进行必要的检查判断, 特别是异常处理 */
        if (context->active_evcc_gbt27930_system->sub_module_func != NULL)
        {
            next_status_id = context->active_evcc_gbt27930_system->sub_module_func(context);

            /* 子过程未引起状态跳转, 则执行当前状态的过程方法, 确认是否可能发生状态切换 */
            if (next_status_id == context->current_module_status_id)
            {
                next_status_id = status->loop_func(context);
            }
        }
        if (next_status_id != context->current_module_status_id)
        {
            OpenChaoJi_evcc_service_switch_status(context, next_status_id);
        }

        /* 最后发送本方数据到对端, 同步本方状态给对端 */
        if (context->active_evcc_gbt27930_system->data_write_func != NULL)
        {
            context->active_evcc_gbt27930_system->data_write_func(context);
        }
    }
    else
    {
        /* 正常来说状态不可能为空, 但是防止编码赋值错误, 这里需要处理空的情况, 需要把系统置为故障状态 */
        LOG_ALERT("[%d] Unknown Status",context->tag);
    }
}


// 初始化上下文, 每一把枪注册一个上下文, 所以本项目支持不同类型系统混合使用
struct OpenChaoJi_evcc_context * OpenChaoJi_evcc_create_context(const struct OpenChaoJi_evcc_context_create_info * info)
{
    struct OpenChaoJi_evcc_context * context = OpenChaoJi_os_malloc(sizeof(struct OpenChaoJi_evcc_context));
    if (context == NULL)
    {
        return NULL;
    }
    memset(context, 0x00, sizeof(struct OpenChaoJi_evcc_context));

    /* 记录hal参数, 供HAL层内部使用 */
    context->hal_handle = info->hal_handle;
    context->tag = info->tag;

    /* 初始化Utiltiy各层 */
    context->context_pilot = OpenChaoJi_evcc_utility_pilot_init(&info->pilot);
    if (context->context_pilot == NULL)
    {
        goto FAILED_CREATE;
    }
    context->context_session = OpenChaoJi_evcc_utility_session_init(&info->session);
    if (context->context_session == NULL)
    {
        goto FAILED_CREATE;
    }

    /* 初始化System A/B可以同时存在 */
    context->evcc_gbt27930_type = info->evcc_gbt27930_type;
    context->secc_gbt27930_type_compatibility = info->secc_gbt27930_type_compatibility;

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
    if ((info->evcc_gbt27930_type == OPENCHAOJI_EVCC_GBT27930_TYPE_A)
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    || ((info->evcc_gbt27930_type == OPENCHAOJI_EVCC_GBT27930_TYPE_B) && (context->secc_gbt27930_type_compatibility & OPENCHAOJI_SECC_GBT27930_TYPE_A))
#endif
    )
    {
        if (OpenChaoJi_evcc_create_system_gbt27930_a(context) != 0)
        {
            goto FAILED_CREATE;
        }
		context->active_evcc_gbt27930_system = context->evcc_gbt27930_system_a;
    }
#endif

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    if (info->evcc_gbt27930_type == OPENCHAOJI_EVCC_GBT27930_TYPE_B)
    {
        if (OpenChaoJi_evcc_create_system_gbt27930_b(context) != 0)
        {
            goto FAILED_CREATE;
        }
		context->active_evcc_gbt27930_system = context->evcc_gbt27930_system_b;
    }
#endif

    if (true
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
        && (context->evcc_gbt27930_system_a == NULL)
#endif
#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
        && (context->evcc_gbt27930_system_b == NULL)
#endif
    )
    {
        LOG_ALERT("[%d]Invalid EVCC/SECC Compatibility", info->tag);
        goto FAILED_CREATE;
    }

    LOG_NOTICE("[%d]Create Context SUCCESS", context->tag);
    return context;

FAILED_CREATE:
    LOG_ALERT("[%d]Create Context FAILED", info->tag);

    OpenChaoJi_evcc_destroy_context(context);

    return NULL;
}

// 销毁一个上下文
void OpenChaoJi_evcc_destroy_context(struct OpenChaoJi_evcc_context * context)
{
    if (context == NULL)
    {
        return;
    }

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_A == CONFIG_YES)
    if (context->evcc_gbt27930_system_a != NULL)
    {
        OpenChaoJi_evcc_destory_system_gbt27930_a(context);
    }
#endif

#if (OPENCHAOJI_CONFIG_ENABLE_GBT27930_B == CONFIG_YES)
    if (context->evcc_gbt27930_system_b != NULL)
    {
        OpenChaoJi_evcc_destory_system_gbt27930_b(context);
    }
#endif

    if (context->context_pilot != NULL)
    {
        OpenChaoJi_evcc_utility_pilot_term(context->context_pilot);
    }
    if (context->context_session != NULL)
    {
        OpenChaoJi_evcc_utility_session_term(context->context_session);
    }

    OpenChaoJi_os_free(context);
}
